function TeamScore() {
	this.ID = "Nobody";
	this.currentProblems = [];
	this.finalProblems = [];
}
var teams = [];
var problemsNumber;

function delayMethod(during, callback) {
	if (callback.name) {
		setTimeout("(" + callback.toString() + ")()", during);
	} else {
		setTimeout("fn = " + callback.toString() + "()", during);
	}
}

function getAcNum(problems) {
	var acNum = 0;
	for (var idx = 0; idx < problems.length; ++idx) {
		var problem = problems[idx];
		acNum += problem.ac ? 1 : 0;
	}
	return acNum;
}

function getPenalty(problems) {
	var penalty = 0;
	for (var idx = 0; idx < problems.length; ++idx) {
		var problem = problems[idx];
		penalty += problem.ac ? problem.time + (problem.tries - 1) * 20 : 0;
	}		
	return penalty;
}

function higherPriority(t1, t2) {
	return getAcNum(t1.currentProblems) > getAcNum(t2.currentProblems) ||
		getAcNum(t1.currentProblems) == getAcNum(t2.currentProblems)
		&& getPenalty(t1.currentProblems) < getPenalty(t2.currentProblems);
}

// only for boards generated by pc2v87
function loadData(callback) {
	var loadDataCallbackFn = callback;
	$("#currentBoard").load(currentBoardFileUrl, function(response, status, xhr){
		if (status == "error") {
			alert(xhr.status+ " "+xhr.statusText);
			return;
		}
		$("#finalBoard").load(finalBoardFileUrl, function(response, status, xhr){
			if (status == "error") {
				alert(xhr.status+ " "+xhr.statusText);
				return;
			}
			
			var teamsNumber = $("#currentBoard tr").length - 3;
			problemsNumber = $("#currentBoard th").length - 5;
			
			$("#currentBoard tr").each(function(index, e){
				if (index > 0 && index <= teamsNumber) {
					var team = new TeamScore();
					$(e).find("td").each(function (index, e) {
						if (index == 1) {
							team.ID = $(e).text();
						} else if (index > 3 && index-4 < problemsNumber ) {
							
							var buf = $(e).text().split("/");
							if (buf[1] == '--') {
								team.currentProblems.push({"ac":false, "tries": parseInt(buf[0]), "time":0});
							} else {
								team.currentProblems.push({"ac":true, "tries": parseInt(buf[0]), "time":parseInt(buf[1])});
							}
						}
					});
					teams.push(team);
				}
			});
			
			$("#finalBoard tr").each(function(index, e){
				if (index > 0 && index <= teamsNumber) {
					var teamname = $(e).find("td:eq(1)").text();
					var team;
					for (var i = 0; i < teams.length; ++i) {
						if (teams[i].ID == teamname) {
							team = teams[i];
							break;
						}
					}
					$(e).find("td").each(function (index, e) {
						if (index == 1) {
							team.ID = $(e).text();
						} else if (index > 3 && index-4 < problemsNumber ) {
							var buf = $(e).text().split("/");
							if (buf[1] == '--') {
								team.finalProblems.push({"ac":false, "tries": parseInt(buf[0]), "time":0});
							} else {
								team.finalProblems.push({"ac":true, "tries": parseInt(buf[0]), "time":parseInt(buf[1])});
							}
						}
					});
				}
			});
			
			
			for (var i = 0; i < teams.length; ++i) {
				for (var j = 0; j < problemsNumber; ++j) {
					if (teams[i].currentProblems[j].tries > teams[i].finalProblems[j].tries || 
						teams[i].finalProblems[j].ac && teams[i].finalProblems[j].time <= 240) {
							teams[i].currentProblems[j].ac = teams[i].finalProblems[j].ac;
							teams[i].currentProblems[j].time = teams[i].finalProblems[j].time;
							teams[i].currentProblems[j].tries = teams[i].finalProblems[j].tries;
						}
				}
			}
			// sort board
			for (var i = 0; i < teams.length; ++i) {
				for (var j = i + 1; j < teams.length; ++j) {
					if (higherPriority(teams[j], teams[i])) {
						var t = teams[i];
						teams[i] = teams[j];
						teams[j] = t;
					}
				}
			}
			
			loadDataCallbackFn();
		});
	});
}

function generateBoard() {
	var cnt = $(".container");
	var newteam = $("#newteam");
	var newstatus = $("#newstatus");
	cnt.css("height", teams.length * teamHeight);
	$(".blank").css("top", teams.length * teamHeight);
	var rank = 1;
	for (var idx = 0; idx < teams.length; ++idx) {
		var team = teams[idx];
		var teamObj = newteam.clone();
		team.obj = teamObj;
		team.rank = rank;
		teamObj
			.appendTo(cnt)
			.removeAttr("id")
			.find(".rank").text(team.rank).end()
			.find(".teamname").text(team.ID).end()
			.find(".acNum").text(getAcNum(team.currentProblems)).end()
			.find(".penalty").text(getPenalty(team.currentProblems)).end()
			.css("top", (rank-1) * teamHeight)
			.css("z-index", teams.length-rank);
		var statusCnt = teamObj.find(".acNum");
		for (var pi = 0; pi < team.currentProblems.length; ++pi) {
			var problem = team.currentProblems[pi];
			var statusObj = newstatus.clone();
			problem.obj = statusObj;
			statusObj.insertBefore(statusCnt).removeAttr("id");			
		
			if (problem.ac) {
				statusObj.addClass(cssYes)
					.find(".tries").text(problem.tries).end()
					.find(".time").text("/" + problem.time);
			} else if (team.finalProblems[pi].tries == 0) {
				statusObj.addClass(cssEmpty);
			} else if (team.finalProblems[pi].tries <= problem.tries) {
				statusObj.addClass(cssNo).find(".tries").text(problem.tries);
			} else {
				statusObj.addClass(cssPending).find(".tries").text(problem.tries);
			}
		}
		++rank;
	}
}

var pointer;
var lastPointer;
var  updateRowCallbackFn;
var timer;
var stop = true;



function moveScroll(idx, callback) {
	$("html,body").animate({"scrollTop": (idx-scrollPosition) * teamHeight}, 200);
	delayMethod(400, callback);	
}

var now;
function updateRank() {
	if (now > 0 && higherPriority(teams[now], teams[now-1])) {
		var t = teams[now];
		teams[now] = teams[now-1];
		teams[now-1] = t;
		t = teams[now].rank;
		teams[now].rank = teams[now-1].rank;
		teams[now-1].rank = t;
		
		teams[now].obj
			.css("z-index", teams.length-teams[now].rank)
			.animate({"top": (teams[now].rank -1)*teamHeight},"fast")
			.find(".rank").text(teams[now].rank);
		teams[now-1].obj
			.css("z-index", teams.length-teams[now-1].rank)
			.animate({"top": (teams[now-1].rank -1)*teamHeight},"fast")
			.find(".rank").text(teams[now-1].rank);			
		--now;
		moveScroll(now, updateRank);
	} else {
		lastPointer = now;
		++pointer;
		updateRowCallbackFn();
	}	
}

var pidx;
function updateRow2() {
	var cp = teams[pointer].currentProblems;
	var fp = teams[pointer].finalProblems;

	while (pidx < problemsNumber) {
		if (cp[pidx].tries < fp[pidx].tries) {
			cp[pidx].tries = fp[pidx].tries;
			cp[pidx].time = fp[pidx].time;
			cp[pidx].ac = fp[pidx].ac;
			cp[pidx].obj
				.switchClass(cssPending, cp[pidx].ac ? cssYes : cssNo, "fast")
				.fadeOut();
			if (cp[pidx].ac) {
				cp[pidx].obj
					.find(".tries").text(cp[pidx].tries).end()
					.find(".time").text("/" + cp[pidx].time+"").end()
					.fadeIn();
			} else {
				cp[pidx].obj
					.find(".tries").text(cp[pidx].tries).end()
					.fadeIn();
			}
				
			if (cp[pidx].ac) {
				now = pointer;
				teams[pointer].obj
					.find(".acNum").text(getAcNum(cp)).end()
					.find(".penalty").text(getPenalty(cp)).end();
				delayMethod(openProblemDelay, updateRank);
			} else {
				delayMethod(openProblemDelay, updateRow2);
			}
			++pidx;			
			return;
		} else {
			++pidx;
		}
	}
	updateRowCallbackFn();
}

function updateRow(callbackFn) {
	updateRowCallbackFn=callbackFn;
	pidx = 0;
	updateRow2();
}

function updateBoard() {
	if (lastPointer >= 0) {
		teams[lastPointer].obj.toggleClass("focus", "slow")
			.find(".item").toggleClass("focus2", "slow");
	}
	if (pointer>=0) {
		delayMethod(startDelay, function(){
			var exec = function() {
				teams[pointer].obj.toggleClass("focus", "slow")
					 .find(".item").toggleClass("focus2", "slow");
				lastPointer = pointer;
				delayMethod(1000, function(){
					updateRow(function(){
						pointer--;
						if (!stop) {
							updateBoard();
						}
					});
				});
			};
			moveScroll(pointer, exec);
		});
	}	
}

function startUpdate() {
	pointer = teams.length -1;
	lastPointer = -1;
	updateBoard();
}

function onPause() {
	stop = !stop;
	if (!stop) {
		updateBoard();
	}
	$("#cntPause").find("span").text(stop?"continue":"pause");
}

$(document).ready(function() {
	$("#cntPause").button().click(onPause);
	$("#boardTitle").text(boardTitle);
	document.title = boardTitle;
	loadData(function(){	
		generateBoard();
		startUpdate();
	});	
});
